﻿
namespace Orz.Framework.Core.Subscriber
{
    using Orz.Framework.Core.Messaging;
    using Orz.Framework.Core.Publisher;

    /// <summary>
    /// Provider a adapter of subscriber, subscribe and handle a specified message type.
    /// Notice that SubscriberAdapter is also a publisher, after handle the message, it can
    /// continue to publish message.
    /// </summary>
    /// <typeparam name="T">Message type.</typeparam>
    public abstract class SubscriberAdapter<T> : PublisherAdapter, ISubscriber
    {
        TypeMessenger messenger = SingletonManager.GetInstance<TypeMessenger>();

        /// <summary>
        /// Subscribe the message handler.
        /// </summary>
        public void Subscribe()
        {
            messenger.Subscribe<T>(new VoidDelegateHandler<T>(msg => Handle(msg)));
        }

        #region IMessageHandler Members

        /// <summary>
        /// Handle a message.
        /// </summary>
        /// <param name="message">The message.</param>
        public void Handle(object message)
        {
            if (IsValid(message))
                OnHandleMessage((T)message);
        }

        #endregion

        /// <summary>
        /// Called when [handle message].
        /// </summary>
        /// <param name="message">The message.</param>
        protected abstract void OnHandleMessage(T message);

        /// <summary>
        /// Publish the message.
        /// </summary>
        /// <param name="message">The message.</param>
        public override void OnMessage(object message)
        {
            if (IsValid(message))
                base.OnMessage(message);
        }

        /// <summary>
        /// Publish the message asynchronously.
        /// </summary>
        /// <param name="message">The message.</param>
        public override void OnMessageAsyn(object message)
        {
            if (IsValid(message))
                base.OnMessageAsyn(message);
        }

        /// <summary>
        /// Determines whether the specified message is valid.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns>
        /// 	<c>true</c> if the specified message is valid; otherwise, <c>false</c>.
        /// </returns>
        protected virtual bool IsValid(object message)
        {
            return message != null && !(message is T);
        }
    }
}
